

#include <stdint.h>
#include <string.h>
#include "BSP_RS485.h"
#include "BSP_Sleep.h"

#include "util.h"
#include "WG.h"
#include "Env.h"

#include "CardDefine.h"
#include "Reader.h"

void Command_Rs485Out(CSN_T *csn);


/*
从卡号获取韦根输出数据
*/
//IC卡韦根卡号转换（标准）
/*
1、WG26正序：
4字节卡：2，3，4
7字节卡：5，6，7

2、WG26反序：
4字节卡：3，2，1
7字节卡：6，5，4

3、WG34正序：
4字节：1，2，3，4
7字节：4，5，6，7

4、WG34反序：
4字节卡：4，3，2，1
7字节卡：7，6，5，4


5、WG66正序：
4字节卡：00，00，00，00，1，2，3，4
7字节卡：88，1，2，3，4，5，6，7

6、WG66反序：
4字节卡：00，00，00，00，4，3，2，1
7字节卡：7，6，5，4，3，2，1，88

*/
#if 0
static void IcCard_WGData_Std(uint8_t reverse, uint8_t wg, 
	uint8_t* ibuf, uint8_t ilen, WGBuf_T* obuf){

	uint8_t wlen = wg / 8;
	uint8_t clen;
	
	if(wlen < 5){
		//WG 26/34
		//截取后4字节
		uint8_t buf[4];
		uint8_t n = Mem_Backward_Copy(buf, 4, ibuf, ilen, 4);
	
		clen = MIN(wlen, n);
		
		if(reverse){
			//反序
			memcpy(obuf->buf, buf, clen);
		}
		else{
			//正序
			Mem_Backward_Copy(obuf->buf, clen, buf, n, clen);
		}
	}
	else{
		clen = MIN(wlen, ilen);
		Mem_Backward_Copy(obuf->buf, clen, ibuf, ilen, clen);
	}	
	obuf->len = clen;
	obuf->reverse = reverse;
}
#endif 

#if 1
static void IcCard_WGData_Std(uint8_t reverse, uint8_t wg, 
	uint8_t* ibuf, uint8_t ilen, WGBuf_T* obuf){

	uint8_t wlen = wg / 8;
	uint8_t clen;
	
	if(wlen < 5){
		//WG 26/34
		//截取后4字节
		uint8_t buf[4];
		memset(buf, 0, sizeof(buf));
		uint8_t n = Mem_Backward_Copy(buf, sizeof(buf), ibuf, ilen, 4);
	
		clen = MIN(wlen, n);
		
		if(reverse){
			//反序
			//memcpy(obuf->buf, buf, wlen);
			Mem_Backward_Copy(obuf->buf, clen, buf, sizeof(buf), clen);
		}
		else{
			//正序
			Mem_Backward_Copy(obuf->buf, wlen, buf, sizeof(buf), clen);
		}
	}
	else{
		clen = MIN(wlen, ilen);
		if(reverse){
			//反序
			Mem_Backward_Copy(obuf->buf, clen, ibuf, ilen, clen);
		}
		else{
			//正序
			Mem_Backward_Copy(obuf->buf, wlen, ibuf, ilen, clen);
		}
	}	
	obuf->len = wlen;
	obuf->reverse = reverse;
}
#endif 

void OutPut_Init(void){

}


void OutPut_Out(uint8_t type, uint8_t buf[], uint8_t len){
	// 韦根格式转换
	WGBuf_T obuf;
	uint8_t reverse = envData.wgReverse;
	if(type == Card_T_CpuB){
		//为兼容老产品，身份证卡号与IC卡号顺序相反。
		reverse = !reverse;
	}
	memset(&obuf, 0, sizeof(obuf));	
	IcCard_WGData_Std(reverse, envData.wg, buf, len, &obuf);
	Wiegand_SendBuf(envData.wg, &obuf);
}

#pragma pack(1)

typedef struct IdentyCardInfoTag{
	uint8_t name[30];
	uint8_t sex[2];
	uint8_t nation[4];
	uint8_t birthDay[16];
	uint8_t address[70];
	uint16_t number[18];
	uint8_t office[30];
	uint8_t startDate[16];
	uint8_t endDate[16];
	uint8_t reserve[36];
}IdentyCardInfo_T;

#pragma pack()


static void Ut16BufToValue(uint16_t* buf, uint8_t blen, uint64_t* val){
	uint16_t i;
	*val = 0;
	for(i = 0; i < blen; i++){
		uint8_t ch = CharToValue(buf[i], 10);
		if(ch > 9){
			break;
		}
		*val = *val * 10 + ch;
	}
}


static void OutPut_GetSFZ_Num(CSN_T* csn, uint8_t *info, uint8_t *len){
	IdentyCardInfo_T* c = (IdentyCardInfo_T*)(csn->ibuf + 14);
	uint64_t val;
	uint16_t number[18];
	
	memcpy(number, c->number, sizeof(c->number));
	Ut16BufToValue(number, 18, &val);
	memcpy(info, (uint8_t*)&val, sizeof(val));
	*len = sizeof(val);
}


static int OutPut_GetData(uint8_t wg, uint8_t reverse, CSN_T* csn, WGBuf_T* obuf){
	// 韦根格式转换
	uint8_t type = csn->std;
	
	if(type == Card_T_CpuB){
		if(csn->ilen){
			//输出身份证号
			uint8_t buf[12];
			uint8_t len;
			OutPut_GetSFZ_Num(csn, buf, &len);
			IcCard_WGData_Std(reverse, wg, buf, len, obuf);
			return 1;
		}
		
		//为兼容老产品，身份证卡号与IC卡号顺序相反。
		reverse = !reverse;
	}
	
	IcCard_WGData_Std(reverse, wg, csn->num, csn->nlen, obuf);
	return 0;
}


static uint8_t CalcWidth(uint8_t len){
	//1个16进制位至少需要1.2个十进制位表示。
	uint32_t t = len * (2 * 12); 
	uint32_t width = t / 10;
	
	if(t % 10){
		width += 1;
	}
	return width;
}
static uint64_t BufToVal(uint8_t reverse, uint8_t* buf, uint8_t len){
	uint64_t v = 0;
	
	if(reverse){
		Mem_Reverse_Copy((uint8_t *) &v, buf, len);
	}
	else{
		memcpy(&v, buf, len);
	}
	
	return v;
}

static uint32_t ValToDecCodes(uint8_t width, uint64_t val, uint8_t code[]){
	uint32_t i;
	uint64_t v = val;	
	
	i = 0;
	do{
		code[i++] = ValueToDecCode(v % 10);
		v /= 10;
	}while(v);
	
	for(; i < width; i++){
		code[i] = '0';
	}
	Mem_Reverse(code, i);
	return i;
}

static uint32_t BufHexToDecSplit(uint8_t num, uint8_t split, WGBuf_T* obuf, uint8_t code[]){
	uint32_t len;
	uint8_t buf[8];
	
	if(obuf->reverse){
		Mem_Reverse_Copy(buf, obuf->buf, obuf->len);
	}
	else{
		memcpy(buf, obuf->buf, obuf->len);
	}
	
	//前半段
	uint64_t v = 0; 
	uint8_t w = CalcWidth(split);
	
	Mem_Reverse_Copy((uint8_t*)&v, buf, split);
	len = ValToDecCodes(w , v, code);
	
	//后半段
	w = CalcWidth(num - split);
	v = 0;
	Mem_Reverse_Copy((uint8_t*)&v, buf + split, num - split);
	len += ValToDecCodes(w , v, code + len);

	return len;
}

//不分段
static uint32_t BufHexToDec(uint8_t num, WGBuf_T* obuf, uint8_t code[]){
	uint32_t len;
	uint64_t v = 0;
	
	if(obuf->reverse){
		memcpy((uint8_t*)&v, obuf->buf, obuf->len);
	}
	else{
		Mem_Reverse_Copy((uint8_t*)&v, obuf->buf, obuf->len);
	}
	
	//固定长度，有前缀0
	len = ValToDecCodes(CalcWidth(num), v, code);
	
	return len;
}


static void OutPut_Split(uint8_t num, uint8_t split, WGBuf_T* obuf){
	uint8_t code[32];
	uint32_t len;
	uint64_t val;
	
	len = BufHexToDecSplit(num, split, obuf, code);
	code[len] = 0;
	DecStrToValue(code, len, &val);
	Wiegand_Send(num * 8, 1, (uint8_t*)&val, num);	
}

static void OutPut_Report(uint8_t wg, uint8_t ch, WGBuf_T* obuf){
	uint8_t code[32];
	uint32_t len;
	uint32_t num = wg / 8;
	uint8_t split = envData.doorUnlockTime;
	uint8_t format = envData.hidFormat;
	uint8_t offset = 0;
	
	if(0 < split && split < num){
		len = BufHexToDecSplit(num, split, obuf, code);
	}
	else{
		len = BufHexToDec(num, obuf, code);
	}
	
	if(format == 0){
		//无前缀0
		while(offset < (len - 1)){
			if(code[offset] != '0'){
				break;
			}
			offset++;
		}
	}
	
	
	if(ch & ENV_CH_485A){
		//串口输出
		
//			BSP_RS485_SetDir(RS485_DIR_OUT);
//			BSP_Sleep_Ms(2);
//			BSP_RS485_RawSend(code + offset, len - offset);
//			BSP_Sleep_Ms(2);
//			BSP_RS485_SetDir(RS485_DIR_IN);
	}
#if 0
	if(ch & ENV_CH_KB){
		//键盘输出
		Keyboard_ReportRaw(code + offset, len - offset);
	}
#endif 
}


void OutPut_CSN(CSN_T* csn){
	uint8_t reverse = envData.wgReverse;
	uint8_t wg = envData.wg;
	WGBuf_T obuf;
	memset(&obuf, 0, sizeof(obuf));	
	
	int ret = OutPut_GetData(wg, reverse, csn, &obuf);
	if(csn->ilen){
		if(!obuf.reverse){
			Mem_Reverse_Copy(csn->ibuf, obuf.buf, obuf.len);
		}
		else{
			memcpy(csn->ibuf, obuf.buf, obuf.len);
		}
		csn->ilen = obuf.len;
	}
	else{
		if(!obuf.reverse){
			Mem_Reverse_Copy(csn->num, obuf.buf, obuf.len);
		}
		else{
			memcpy(csn->num, obuf.buf, obuf.len);
		}
		
		csn->nlen = obuf.len;
	}
	
	if(ret){
		Wiegand_SendBuf(wg, &obuf);
		Command_Rs485Out(csn);
	}
	else{
		uint32_t num = wg / 8;
		uint8_t split = envData.doorUnlockTime;
		if(0 < split && split < num){
			OutPut_Split(num, split, &obuf);
			Command_Rs485Out(csn);
		}
		else{
			Wiegand_SendBuf(wg, &obuf);
			Command_Rs485Out(csn);
		}
	}
	uint8_t ch = envData.channelEnable;
	OutPut_Report(wg, ch, &obuf);
}

void OutPut_Key(uint8_t kval){
	uint8_t b = kval | ((0x0F - kval) << 4);
	WG_Send(&b, sizeof(b) * 8, 0);
}


